<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Wan-AI 视频生成体验</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
            color: #333;
        }

        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            overflow: hidden;
        }

        .header {
            background: #4a5568;
            color: white;
            padding: 20px;
            text-align: center;
        }

        .header h1 {
            margin-bottom: 10px;
        }

        .content {
            padding: 30px;
        }

        .form-group {
            margin-bottom: 20px;
        }

        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
        }

        input, select, textarea {
            width: 100%;
            padding: 12px;
            border: 2px solid #e2e8f0;
            border-radius: 8px;
            font-size: 16px;
            transition: border-color 0.3s;
        }

        input:focus, select:focus, textarea:focus {
            outline: none;
            border-color: #667eea;
        }

        textarea {
            height: 100px;
            resize: vertical;
        }

        .radio-group {
            display: flex;
            gap: 20px;
            margin-bottom: 15px;
        }

        .radio-option {
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .radio-option input {
            width: auto;
        }

        .image-upload {
            border: 2px dashed #cbd5e0;
            border-radius: 8px;
            padding: 20px;
            text-align: center;
            cursor: pointer;
            transition: border-color 0.3s;
        }

        .image-upload:hover {
            border-color: #667eea;
        }

        .image-upload.dragover {
            border-color: #667eea;
            background-color: #f7fafc;
        }

        #imagePreview {
            max-width: 100%;
            max-height: 200px;
            margin-top: 10px;
            display: none;
        }

        button {
            background: #667eea;
            color: white;
            border: none;
            padding: 15px 30px;
            border-radius: 8px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            width: 100%;
            transition: background 0.3s;
        }

        button:hover {
            background: #5a6fd8;
        }

        button:disabled {
            background: #a0aec0;
            cursor: not-allowed;
        }

        .result {
            margin-top: 30px;
            display: none;
        }

        .status {
            padding: 15px;
            border-radius: 8px;
            margin-bottom: 15px;
            text-align: center;
        }

        .status.pending {
            background: #fff3cd;
            color: #856404;
        }

        .status.success {
            background: #d1ecf1;
            color: #0c5460;
        }

        .status.error {
            background: #f8d7da;
            color: #721c24;
        }

        #videoResult {
            width: 100%;
            border-radius: 8px;
            margin-top: 15px;
        }

        .loading {
            display: inline-block;
            width: 20px;
            height: 20px;
            border: 3px solid #f3f3f3;
            border-top: 3px solid #667eea;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            margin-right: 10px;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    </style>
</head>
<body>
<div class="container">
    <div class="header">
        <h1>🎬 Wan-AI 视频生成体验</h1>
        <p>支持文生视频和图生视频两种模式</p>
    </div>

    <div class="content">
        <div class="form-group">
            <label for="apiKey">API Key</label>
            <input type="text" id="apiKey" value="sk-laazbuiqreiawuymokbyirubefyxfpfovaexzqtjxcuwrhuo" readonly>
        </div>

        <div class="form-group">
            <label>生成模式</label>
            <div class="radio-group">
                <div class="radio-option">
                    <input type="radio" id="textToVideo" name="mode" value="text" checked>
                    <label for="textToVideo">文生视频</label>
                </div>
                <div class="radio-option">
                    <input type="radio" id="imageToVideo" name="mode" value="image">
                    <label for="imageToVideo">图生视频</label>
                </div>
            </div>
        </div>

        <div class="form-group" id="imageUploadGroup" style="display: none;">
            <label for="imageInput">上传图片（仅图生视频需要）</label>
            <div class="image-upload" id="imageDropZone">
                <p>点击选择图片或拖拽图片到这里</p>
                <input type="file" id="imageInput" accept="image/*" style="display: none;">
                <img id="imagePreview" alt="图片预览">
            </div>
        </div>

        <div class="form-group">
            <label for="prompt">描述提示词</label>
            <textarea id="prompt" placeholder="请输入视频的描述，例如：一只可爱的猫咪在草地上玩耍..."></textarea>
        </div>

        <div class="form-group">
            <label for="negativePrompt">负面提示词（可选）</label>
            <textarea id="negativePrompt" placeholder="不希望出现在视频中的内容..."></textarea>
        </div>

        <div class="form-group">
            <label for="imageSize">视频尺寸</label>
            <select id="imageSize">
                <option value="1280x720">1280x720（横屏）</option>
                <option value="720x1280">720x1280（竖屏）</option>
                <option value="960x960">960x960（方形）</option>
            </select>
        </div>

        <div class="form-group">
            <label for="seed">随机种子（可选）</label>
            <input type="number" id="seed" placeholder="留空则随机生成">
        </div>

        <button id="generateBtn">生成视频</button>

        <div class="result" id="resultSection">
            <div class="status" id="statusMessage"></div>
            <video id="videoResult" controls></video>
        </div>
    </div>
</div>

<script>
    // 元素引用
    const textToVideoRadio = document.getElementById('textToVideo');
    const imageToVideoRadio = document.getElementById('imageToVideo');
    const imageUploadGroup = document.getElementById('imageUploadGroup');
    const imageInput = document.getElementById('imageInput');
    const imageDropZone = document.getElementById('imageDropZone');
    const imagePreview = document.getElementById('imagePreview');
    const apiKeyInput = document.getElementById('apiKey');
    const promptInput = document.getElementById('prompt');
    const negativePromptInput = document.getElementById('negativePrompt');
    const imageSizeSelect = document.getElementById('imageSize');
    const seedInput = document.getElementById('seed');
    const generateBtn = document.getElementById('generateBtn');
    const resultSection = document.getElementById('resultSection');
    const statusMessage = document.getElementById('statusMessage');
    const videoResult = document.getElementById('videoResult');

    // 模式切换
    textToVideoRadio.addEventListener('change', toggleMode);
    imageToVideoRadio.addEventListener('change', toggleMode);

    function toggleMode() {
        if (imageToVideoRadio.checked) {
            imageUploadGroup.style.display = 'block';
        } else {
            imageUploadGroup.style.display = 'none';
            imagePreview.style.display = 'none';
            imagePreview.src = '';
        }
    }

    // 图片上传处理
    imageDropZone.addEventListener('click', () => imageInput.click());
    imageInput.addEventListener('change', handleImageSelect);

    // 拖拽功能
    imageDropZone.addEventListener('dragover', (e) => {
        e.preventDefault();
        imageDropZone.classList.add('dragover');
    });

    imageDropZone.addEventListener('dragleave', () => {
        imageDropZone.classList.remove('dragover');
    });

    imageDropZone.addEventListener('drop', (e) => {
        e.preventDefault();
        imageDropZone.classList.remove('dragover');
        if (e.dataTransfer.files.length) {
            imageInput.files = e.dataTransfer.files;
            handleImageSelect();
        }
    });

    function handleImageSelect() {
        const file = imageInput.files[0];
        if (file && file.type.startsWith('image/')) {
            const reader = new FileReader();
            reader.onload = (e) => {
                imagePreview.src = e.target.result;
                imagePreview.style.display = 'block';
            };
            reader.readAsDataURL(file);
        }
    }

    // 生成视频
    generateBtn.addEventListener('click', generateVideo);

    async function generateVideo() {
        // 验证输入
        if (!promptInput.value.trim()) {
            alert('请输入描述提示词');
            return;
        }

        if (imageToVideoRadio.checked && !imageInput.files[0]) {
            alert('请选择一张图片');
            return;
        }

        // 禁用按钮并显示加载状态
        generateBtn.disabled = true;
        generateBtn.innerHTML = '<span class="loading"></span>生成中...';

        // 显示结果区域
        resultSection.style.display = 'block';
        statusMessage.className = 'status pending';
        statusMessage.innerHTML = '<span class="loading"></span>提交生成请求中...';
        videoResult.src = '';

        try {
            // 准备请求数据
            const requestData = {
                model: imageToVideoRadio.checked ? 'Wan-AI/Wan2.1-I2V-14B-720P' : 'Wan-AI/Wan2.2-T2V-A14B',
                prompt: promptInput.value.trim(),
                image_size: imageSizeSelect.value,
                negative_prompt: negativePromptInput.value.trim() || undefined,
                seed: seedInput.value ? parseInt(seedInput.value) : undefined
            };

            // 如果是图生视频，添加图片数据
            if (imageToVideoRadio.checked && imageInput.files[0]) {
                const base64Image = await fileToBase64(imageInput.files[0]);
                requestData.image = base64Image;
            }

            console.log('发送请求数据:', requestData);

            // 提交生成请求（通过代理）
            const submitResponse = await fetch('http://localhost:3001/api/generate-video', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(requestData)
            });

            if (!submitResponse.ok) {
                const errorText = await submitResponse.text();
                throw new Error(`提交失败: ${submitResponse.status} - ${errorText}`);
            }

            const submitResult = await submitResponse.json();
            console.log('提交响应:', submitResult);

            const requestId = submitResult.requestId;

            if (!requestId) {
                throw new Error('未收到有效的请求ID');
            }

            statusMessage.innerHTML = '<span class="loading"></span>视频生成中，请稍候...';

            // 轮询获取结果（通过代理）
            let videoUrl = null;
            let attempts = 0;
            const maxAttempts = 6000; // 最多尝试5分钟（5秒一次）

            while (!videoUrl && attempts < maxAttempts) {
                await new Promise(resolve => setTimeout(resolve, 5000)); // 每5秒检查一次

                // 使用代理服务器查询状态（POST 请求）
                const statusResponse = await fetch(`http://localhost:3001/api/status`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({ requestId })
                });

                if (statusResponse.ok) {
                    const statusResult = await statusResponse.json();
                    console.log('状态查询结果:', statusResult);

                    // 根据实际的 API 响应格式解析
                    if (statusResult.status === 'Succeed' && statusResult.results && statusResult.results.videos && statusResult.results.videos[0]) {
                        videoUrl = statusResult.results.videos[0].url;
                        break;
                    } else if (statusResult.status === 'failed' || statusResult.status === 'Failed') {
                        throw new Error('视频生成失败: ' + (statusResult.reason || '未知错误'));
                    }
                    // 如果状态是 pending 或 processing，继续等待
                } else {
                    const errorText = await statusResponse.text();
                    console.error('状态查询失败:', errorText);
                }

                attempts++;
                statusMessage.innerHTML = `<span class="loading"></span>视频生成中... (${attempts}/${maxAttempts})`;
            }

            if (videoUrl) {
                statusMessage.className = 'status success';
                statusMessage.innerHTML = '✅ 视频生成成功！';
                videoResult.src = videoUrl;
            } else {
                throw new Error('生成超时，请稍后重试');
            }

        } catch (error) {
            statusMessage.className = 'status error';
            statusMessage.innerHTML = `❌ 错误: ${error.message}`;
            console.error('生成视频失败:', error);
        } finally {
            // 恢复按钮状态
            generateBtn.disabled = false;
            generateBtn.innerHTML = '生成视频';
        }
    }


    // 将文件转换为Base64
    function fileToBase64(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = () => resolve(reader.result);
            reader.onerror = reject;
            reader.readAsDataURL(file);
        });
    }
</script>
</body>
</html>
